/*--------------------------------------------------------------------------------------*\
**
** adv_ferry.cpp
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "adventure_events_base.h"

#include "adventure_map.h"
#include "adventure_object.h"
#include "adventure_object_ptr.h"
#include "army.h"
#include "compressed_filter.h"
#include "float_object.h"
#include "game_time.h"
#include "saved_game_header.h"
#include "town.h"

/////////////////////////////////////////////////////////////////////////
//Common functions used by the adventure events and its derived classes.
//Has its own namespace.
//
// --------------------------------------------------------------------------
// k_memory_event_buffer_size : defines the desired working size of the in memory buffer
// object. memory buffers keep a working buffer which is preallocated to avoid constantly
// growing the vector.
// --------------------------------------------------------------------------
int t_adventure_event_functions::k_memory_event_buffer_size = 200;

// --------------------------------------------------------------------------
// seralize the adv_object + header and reutrn the in memory buffer, compacted so as to save space
// --------------------------------------------------------------------------
t_memory_buffer_counted_ptr		t_adventure_event_functions::create_event_buffer(t_adventure_object * adv_object)
{
	assert(adv_object!=NULL);

	t_memory_buffer_counted_ptr			save_buffer( new t_memory_buffer_counted ( t_adventure_event_functions::k_memory_event_buffer_size ) );
	
	{
		//deflate stream witihin its own block to force its destructor call upon 
		//leaving the block (finishes write on buffer)
		
		t_deflate_filter		deflate_buffer( *save_buffer );
		t_saved_game_header		empty_header;
		
		adv_object->get_map()->write_adventure_object ( deflate_buffer , empty_header ,  adv_object );
		
		deflate_buffer.pubsync();
	}
	
	save_buffer->pubsync();
	
	save_buffer->compact();
	
	return save_buffer;
}

// --------------------------------------------------------------------------
// seralize the adv_object and reutrn the in memory buffer, compacted so as to save space
// --------------------------------------------------------------------------
t_memory_buffer_counted_ptr		t_adventure_event_functions::create_state_cahce_buffer(t_adventure_object * adv_object)
{
	assert(adv_object!=NULL);

	t_memory_buffer_counted_ptr save_buffer =  new t_memory_buffer_counted ( t_adventure_event_functions::k_memory_event_buffer_size );
	
	{	
		t_deflate_filter		deflate_buffer( *save_buffer );
		t_saved_game_header		empty_header;
		
		adv_object->write_object ( deflate_buffer );
		
		deflate_buffer.pubsync();
	}
	
	save_buffer->pubsync();
	
	save_buffer->compact();

	return save_buffer;
}

// --------------------------------------------------------------------------
// read the objects state from a cahced state buffer.
// --------------------------------------------------------------------------
void					t_adventure_event_functions::read_object_from_state_cache (t_adventure_object * adv_object, 
																  t_memory_buffer_counted_ptr event_buffer_state )
{
	assert(adv_object!=NULL);

	t_inflate_filter					inflate_buffer( *event_buffer_state );
	int									version = adv_object->get_version();

	/////////////////////////////////////////////////////////////////////////////////

	t_army * army = dynamic_cast<t_army*>(adv_object);
	
	if (army!=NULL)
	{	
		t_float_object floater( army );
		
		army->clear();

		bool is_mobile		= get<bool>( inflate_buffer );
	
		army->read ( inflate_buffer , version );
		
		army->update_state();

		return ;
	}	
	
	/////////////////////////////////////////////////////////////////////////////////

	t_stationary_adventure_object * stationary_adv_obj = dynamic_cast<t_stationary_adventure_object*>(adv_object);
	
	if (stationary_adv_obj!=NULL)
	{
		t_float_object floater( stationary_adv_obj );

		t_qualified_adv_object_type			model_type;
		std::string							model_name;

		bool is_mobile		= get<bool>( inflate_buffer );
		
		read_string16( inflate_buffer, model_name );

		if (!::read( inflate_buffer, model_type ))
			return;
		
		stationary_adv_obj->read ( inflate_buffer , model_type, version );
		
		stationary_adv_obj->update_state();

		return ;
	}

	return ;
}

// --------------------------------------------------------------------------
// creates a adv_object using the maps adv_object creation function.
// --------------------------------------------------------------------------
t_adventure_object* 	t_adventure_event_functions::create_and_place_adv_object( 
																				   t_adventure_map* map, 
																				   t_memory_buffer_counted_ptr adv_buffer, 
																				   t_saved_game_header const & header)
{
	adv_buffer->reset_for_read();

	t_adventure_object_ptr				adv_object;
	t_inflate_filter					inflate_buffer( *adv_buffer );
	
	map->read_and_place_adventure_object( inflate_buffer, header, adv_object );
	
	return adv_object;
}

/////////////////////////////////////////////////////////////////////////
//t_adventure_event_base : a base class which defines the common functionality
//of the adventure_event classes.

t_adventure_event_base::t_adventure_event_base ( int event_type )
{
	m_event_type = event_type;
	
	m_event_tick		= 0;
	m_global_id			= k_invalid_global_id;
	m_is_finished		= false;
	m_player_turn_on	= 0;
	m_time_end			= 0;
	m_is_valid			= true;
}

bool t_adventure_event_base::attach_event_to_cache( t_adventure_map* map )
{
	t_adventure_object * object = map->get_adventure_object_with_gid ( m_global_id );

	if (object == NULL) 
		return false;

	map->attach_event_to_state_cache( object , this );

	return true;
}

void t_adventure_event_base::cancel_event(){}

void t_adventure_event_base::execute_event( t_adventure_map* map , t_saved_game_header const & header ){}

void t_adventure_event_base::undo_event( t_adventure_map* map , t_saved_game_header const & header ){}

// --------------------------------------------------------------------------
// finished : call the callback for this event so the playback object knows the event has finished
// events are modal in that only 1 event can be played at any one time.
// --------------------------------------------------------------------------
bool t_adventure_event_base::finished( )
{ 
	m_is_finished = true;
	m_adv_event_handler(this);
	return true;
}

bool t_adventure_event_base::is_valid()
{
	return m_is_valid;
}

int	t_adventure_event_base::get_team_turn_on( )
{
	return m_player_turn_on;
}

bool t_adventure_event_base::read( std::streambuf & buffer , int version )
{ 
	m_global_id			= read_adventure_global_id(buffer);
	m_player_turn_on	= get<int>(buffer);
	if (version >= 27)
		m_event_tick	= get<unsigned int>(buffer);
	
	return true;
}

bool t_adventure_event_base::write( std::streambuf & buffer ) 
{ 
	write_adventure_global_id(buffer, m_global_id);
	put<int>(buffer,m_player_turn_on);
	put<unsigned int>(buffer,m_event_tick);

	return true;
}

void t_adventure_event_base::update( )
{
	if (m_is_finished) 
		return;
	
	if (m_time_end < get_time())
		finished();
}

int	 t_adventure_event_base::get_event_type(){return m_event_type;}

void t_adventure_event_base::set_handler( t_adventure_event_handler const& handler )
{
	m_adv_event_handler = handler;    
}
